/*
Copyright © 2021 NAME HERE <EMAIL ADDRESS>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd

import (
	"bufio"
	"fmt"
	"gitee.com/maomaomaoge/go-utils/buff"
	"github.com/spf13/cobra"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"strings"
	"time"
)

// keepServeCmd represents the keepServe command
var keepServeCmd = &cobra.Command{
	Use:   "keepServe [port]",
	Short: "tcp 长连接传输",
	Long:  `tcp 长连接传输`,
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			log.Println("少port参数")
			return
		}

		dataQueue := make(chan []byte, 1)
		go keepServe(dataQueue, args[0])

		r := bufio.NewReader(os.Stdin)

		for {
			fmt.Println("输入上传文件的路径")
			readStr, err := r.ReadString('\n')
			if err != nil {
				continue
			}

			file, err := ioutil.ReadFile(strings.TrimSpace(readStr))
			if err != nil {
				log.Println(err)
				return
			}

			bytes := pack(readStr, file)
			dataQueue <- bytes
		}

	},
}

func init() {
	rootCmd.AddCommand(keepServeCmd)
}

type Manger struct {
	Kv map[int]*net.TCPConn
	fl int
}

func keepServe(dataQueue chan []byte, port string) {
	m := &Manger{Kv: make(map[int]*net.TCPConn)}

	localAddress, _ := net.ResolveTCPAddr("tcp4", "0.0.0.0:"+port) //定义一个本机IP和端口。
	tcpListener, err := net.ListenTCP("tcp", localAddress)         //在刚定义好的地址上进监听请求。
	if err != nil {
		fmt.Println("监听出错：", err)
		return
	}
	defer func() { //担心return之前忘记关闭连接，因此在defer中先约定好关它。
		tcpListener.Close()
	}()

	fmt.Println("长连接服务: ", port)

	for {
		conn, err := tcpListener.AcceptTCP() //接受连接。
		if err != nil {
			fmt.Println("接受连接失败：")
			return
		}
		fmt.Println("收到链接")
		err = conn.SetKeepAlive(true)
		if err != nil {
			log.Println(err)
		}

		m.Kv[m.fl] = conn
		fmt.Println("收到订阅: ", m.fl)
		m.fl++

		go keepServerRead(conn)

		// 写的服务
		go func() {
			for {
				d := <-dataQueue
				for _, v := range m.Kv {
					v.Write(d)
				}
			}

		}()
	}

}

func keepServerRead(conn *net.TCPConn) {
	now := time.Now()
	// 第一次读取消息字节数
	data := make([]byte, 4)
	_, err := conn.Read(data)
	if err != nil {
		log.Println(err)
		return
	}
	buf := buff.NewBufferBytes(data)
	allDataLen := buf.Int()
	fmt.Println("总大小:/mb ", float64(allDataLen)/1024/1024)

	// 第一次读取文件名的字节数
	data = make([]byte, 4)
	_, err = conn.Read(data)
	if err != nil {
		log.Println(err)
		return
	}
	buf = buff.NewBufferBytes(data)
	fileNameByte := buf.Int()

	// 解析文件名字
	data = make([]byte, fileNameByte)
	_, err = conn.Read(data)
	if err != nil {
		log.Println(err)
		return
	}
	fileNameSlice := strings.Split(strings.ReplaceAll(string(data), `\`, `/`), `/`)
	fileName := fileNameSlice[len(fileNameSlice)-1]
	fmt.Println("解析的文件名字为: ", fileName)

	os.RemoveAll(fileName)
	f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC|os.O_APPEND, os.ModePerm)
	if err != nil {
		log.Println(err)
		return
	}

	var curByte int
	for {
		// todo: 可以尝试每一次大点字节的读取
		tmpData := make([]byte, 1024*1024*5)
		read, err := conn.Read(tmpData)
		if err != nil || err == io.EOF {
			break
		}

		f.Write(tmpData[:read])
		f.Seek(1, read)
		curByte += read
		fmt.Println("当前进度:% ", float64(curByte)/float64(allDataLen)*100)
	}

	fmt.Println("上传完成")
	f.Close()

	fmt.Println("文件总大小:/mb ", float64(allDataLen)/1024/1024)
	fmt.Println("总用时: ", time.Since(now).String())

	fmt.Println("平均速度:/mb/s ", float64(allDataLen)/1024/1024/time.Since(now).Seconds())
}

